package com.allwees.bs.module.oms.service.impl;


import com.allwees.bs.core.model.order.wf.order.EOrderState;
import com.allwees.bs.core.model.payment.enums.EPaymentType;
import com.allwees.bs.core.modelbase.constant.ResultCode;
import com.allwees.bs.core.modelbase.constant.ResultEnum;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.bs.module.lms.dao.LogisticsWaybillDao;
import com.allwees.bs.module.lms.entity.Logistics;
import com.allwees.bs.module.lms.entity.LogisticsWaybill;
import com.allwees.bs.module.oms.account.runner.AccountTransitUtils;
import com.allwees.bs.module.oms.entity.OmsOrder;
import com.allwees.bs.module.oms.entity.OmsOrderItem;
import com.allwees.bs.module.oms.entity.Order;
import com.allwees.bs.module.oms.entity.OrderItem;
import com.allwees.bs.module.oms.req.RetailerCancelShippedReq;
import com.allwees.bs.module.oms.req.RetailerShippedReq;
import com.allwees.bs.module.oms.service.RetailerOmsOrderItemService;
import com.allwees.bs.module.oms.service.RetailerOmsOrderService;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.common.i18n.MessageSourceUtil;
import com.allwees.support.payment.oceanpay.client.OceanpayRequestClient;
import com.allwees.support.payment.oceanpay.config.OceanpayProperties;
import com.allwees.support.payment.oceanpay.dto.LogisticsUploadRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 零售商 oms item order
 *
 * @author mouhaining
 * @since 2020-02-28 15:58
 */
@Slf4j
@Service
public class RetailerOmsOrderItemServiceImpl extends BaseOmsOrderItemServiceImpl implements RetailerOmsOrderItemService {

    @Autowired
    private RetailerOmsOrderService retailerOmsOrderService;

    @Autowired
    private AccountTransitUtils accountTransitUtils;

    @Resource
    protected LogisticsWaybillDao logisticsWaybillDao;

    @Autowired
    private OceanpayProperties properties;

    @Override
    @Transactional
    public void doShipped(RetailerShippedReq req) {
        Logistics logistics = logisticsDao.findByUuid(req.getLogisticsUuid());
        Assert.notNull(logistics, "此物流公司不存在");
        Set<String> orderItemUuids = req.getOrderItemUuids();
        List<LogisticsWaybill> waybills = logisticsWaybillDao.findByUuids(orderItemUuids);
        Assert.isTrue(CollectionUtils.isEmpty(waybills), "不能重复发货");

        Date now = new Date();
        String expressCode = req.getExpressCode().trim();
        for (String orderItemUuid : orderItemUuids) {
            OmsOrderItem omsOrderItem = checkByUuid(orderItemUuid);

            Assert.isTrue(omsOrderItem.getCanShipping(), "订单正在冻结中");
            Assert.isTrue(omsOrderItem.getStatus().equals(EStatus.OMS_WAIT_MERCHANT_SHIP.getValue()), "当前状态不可发货");

            //发货
            _doShipped(orderItemUuid, req.getLogisticsUuid(), expressCode, now, logistics);
            //accountService.doInShippingAmt(omsOrderItem);
            accountTransitUtils.accountTransit(omsOrderItem, "doInShippingAmt");

            //物流信息
            _saveLogisticsWaybill(orderItemUuid, omsOrderItem.getOrderUuid(), expressCode, now, logistics.getCode());

            //创建关注物流信息
            _saveTrackingLogisticsWaybill(expressCode, logistics.getCode());

            //更新运费统计
            OmsOrder omsOrder = _updateShippedCount(omsOrderItem.getOrderUuid());

            //oceanpay支付需上报物流信息
            uploadLogisticsInfo(omsOrder, expressCode);
        }

        retailerOmsOrderService.doShipped(baseMapper.findOrderUuids(orderItemUuids));
        // 日志
        _saveShippedLog(orderItemUuids, req.getLogisticsUuid(), expressCode);
    }

    private void uploadLogisticsInfo(OmsOrder omsOrder, String expressCode) {
        if (omsOrder.getPaymentType() == EPaymentType.OCEANPAY) {
            log.info("===>upload logistics info to oceanpay,orderUuid:{},shippedCount:{},quantity:{}", omsOrder.getUuid(), omsOrder.getShippedCount(), omsOrder.getQuantity());
            LogisticsUploadRequest request = new LogisticsUploadRequest();
            int quantity = omsOrder.getQuantity();
            /*
                绝大多数情况下一个order都只有一个子单，此种情况直接使用物流单号，可以少一次回表；
                如果不是一个子单且所有子单没有全部发货就不进行上报，否则可能出现漏单；

             */
            if (quantity != 1 && quantity != omsOrder.getShippedCount()) {
                return;
            }

            if (quantity == 1) {
                request.setTracking_number(expressCode);
            } else {
                List<OrderItem> list = orderItemDao.findByOrderUuid(omsOrder.getUuid());
                log.info("===>upload logistics info to oceanpay,order item size:{}", list.size());
                String trackingNums = list.stream().map(OrderItem::getExpressCode).collect(Collectors.joining(","));
                request.setTracking_number(trackingNums);
            }
            request.setAccount(properties.getAccount());
            request.setTerminal(properties.getTerminal());
            request.setOrder_number(omsOrder.getUuid());
            OceanpayRequestClient.sendUploadLogistRequest(request, properties.getSecureCode());
        }
    }

    private OmsOrder _updateShippedCount(String orderUuid) {
        OmsOrder omsOrder = omsOrderDao.findByUuid(orderUuid);
        OmsOrder update = new OmsOrder();
        int shippedCount = (omsOrder.getShippedCount() != null ? omsOrder.getShippedCount() : 0) + 1;
        update.setShippedCount(shippedCount);
        omsOrderDao.updateByUuid(update, orderUuid);
        omsOrder.setShippedCount(shippedCount);
        return omsOrder;
    }

    @Override
    @Transactional
    public void doCancelShipped(RetailerCancelShippedReq req, String retailerUuid) {
        OrderItem orderItem = orderItemDao.findByUuid(req.getOrderItemUuid());
        if (null == orderItem) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND.getCode(),
                    MessageSourceUtil.getMessage(Locale.US, ResultEnum.NOT_FOUND));
        }

        if (!orderItem.getRetailerUuid().equals(retailerUuid)) {
            throw BusinessException.getInstance(ResultEnum.DATA_NO_PRIVILEGE.getCode(),
                    MessageSourceUtil.getMessage(Locale.US, ResultEnum.DATA_NO_PRIVILEGE));
        }
        OmsOrderItem omsOrderItem = omsOrderItemDao.findByUuid(req.getOrderItemUuid());
        if (null == omsOrderItem) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND.getCode(),
                    MessageSourceUtil.getMessage(Locale.US, ResultEnum.NOT_FOUND));
        }
        Order order = orderDao.findByUuid(orderItem.getOrderUuid());
        if (null == order) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND.getCode(),
                    MessageSourceUtil.getMessage(Locale.US, ResultEnum.NOT_FOUND));
        }
        if (EPaymentType.COD.equals(order.getPaymentType())) {
            return;
        }
        if (!EOrderState.WAIT_SHIP.equals(order.getState())) {
            throw BusinessException.getInstance(ResultEnum.ORDER_CANNOT_REQUEST_REFUND.getCode(),
                    MessageSourceUtil.getMessage(Locale.US, ResultEnum.ORDER_CANNOT_REQUEST_REFUND));
        }
        retailerOmsOrderService.doCancelShipped(req, orderItem, order, omsOrderItem);
    }
}
